package clue

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/area"
	userRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/clue"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/crm"
	contract5 "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/crm/contract"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/crm/gfyx_crm_config"
	gfyxcrmrelation2 "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/crm/gfyx_crm_relation"
	customerRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/customer"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/openapi_remote"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/opensearch_remote"
	businessOpportunityPb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/business_opportunity"
	pb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/clue"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/service/business_opportunity/oppty_status"
	"git.myscrm.cn/golang/common/uuid"
	"git.myscrm.cn/golang/stark/v4"
	"strings"
	"time"
)

type clueService struct {
	clueRepo           clue.ClueRepositoryIface
	customerRepo       customerRepo.CustomerRepoIface
	crmConfigRepo      gfyx_crm_config.GfyxCrmConfigRepositoryIface
	crmRelationRepo    gfyxcrmrelation2.GfyxCrmRelationRepositoryIface
	userNewRepos       userRepo.UserRepositoryIface
	userOrgRepos       userRepo.UserOrgRepositoryIface
	areaRepo           area.AreaConfigRepositoryIface
	openSearchRepos    opensearch_remote.OpenSearchRepositoryIface
	opptyStatusService oppty_status.OpptyStatusServiceIface
	openApiRepo        openapi_remote.OpenApiRepoIface
}

func NewClueService(
	clueRepo clue.ClueRepositoryIface,
	customerRepo customerRepo.CustomerRepoIface,
	crmConfigRepo gfyx_crm_config.GfyxCrmConfigRepositoryIface,
	crmRelationRepo gfyxcrmrelation2.GfyxCrmRelationRepositoryIface,
	userNewRepos userRepo.UserRepositoryIface,
	userOrgRepos userRepo.UserOrgRepositoryIface,
	areaRepo area.AreaConfigRepositoryIface,
	openSearchRepos opensearch_remote.OpenSearchRepositoryIface,
	opptyStatusService oppty_status.OpptyStatusServiceIface,
	openApiRepo openapi_remote.OpenApiRepoIface,
) ClueServiceIface {
	return &clueService{
		clueRepo:           clueRepo,
		customerRepo:       customerRepo,
		crmConfigRepo:      crmConfigRepo,
		crmRelationRepo:    crmRelationRepo,
		userNewRepos:       userNewRepos,
		userOrgRepos:       userOrgRepos,
		areaRepo:           areaRepo,
		openSearchRepos:    openSearchRepos,
		opptyStatusService: opptyStatusService,
		openApiRepo:        openApiRepo,
	}
}

func (s *clueService) AddClueSourceFollow(ctx context.Context, request *pb.AddClueSourceFollowRequest) (isNewClue bool, err error) {
	//0.入参校验
	if request == nil || request.ContactMobile == "" {
		return false, errors.New("参数错误")
	}
	curUser := s.getCurUser(ctx)
	//1.检查线索是否存在
	count, _, _ := s.clueRepo.ClueQueryList(ctx,
		map[string]interface{}{
			"a.contact_mobile": request.ContactMobile,
			"a.created_by":     curUser.UserId,
			"a.is_deleted":     constants.IsDeletedFalse,
		}, nil)
	if count > 0 {
		isNewClue = false
		// 线索已经存在，不再新建，直接返回已存在
		return
	}

	isNewClue = true
	//线索不存在，新增线索
	var newClueId int64
	newClueId, err = s.saveNewClue(ctx, &pb.SaveClueRequest{
		Id:              0,
		ContactName:     request.ContactName,
		ContactMobile:   request.ContactMobile,
		CompanyName:     request.CompanyName,
		OrganizingCode:  request.OrganizingCode,
		Source:          request.Source,
		SourceId:        request.SourceId,
		SourceTitle:     request.SourceTitle,
		ProvinceCode:    request.ProvinceCode,
		CityCode:        request.CityCode,
		Status:          request.ClueStatus,
		InChargeUserId:  curUser.UserId,
		ContactPosition: request.ContactPosition,
	})
	if err != nil {
		return
	}

	_, list, _ := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{"clue_id": newClueId, "mobile": request.ContactMobile, "is_deleted": constants.IsDeletedFalse}, nil)
	var contactId int64
	if len(list) > 0 {
		contactId = list[0].Id
	}

	//同时新增跟进记录
	_, err = s.clueRepo.ClueSaveFollowRecord(ctx, &clue.GfyxClueFollowRecordPo{
		Id:               0,
		ClueId:           newClueId,
		ContactId:        contactId,
		FollowType:       request.FollowType,
		FollowStatus:     request.FollowStatus,
		ClueStatus:       request.ClueStatus,
		BeforeClueStatus: 0,
		Content:          request.Content,
		TalkContent:      "",
		FromSource:       constants.ClueFollowFromSourceHuman,
		CreatedBy:        curUser.UserId,
		CreatedOn:        time.Now(),
		ModifiedBy:       curUser.UserId,
		ModifiedOn:       time.Now(),
		IsDeleted:        constants.IsDeletedFalse,
	})
	return true, err
}

func (s *clueService) getOrganizingCodeByCompanyName(ctx context.Context, request *pb.SaveClueRequest) error {
	if request.OrganizingCode == "" && request.CompanyName != "" {
		companyDetail, err := s.openApiRepo.GetCompanyDetail(ctx, request.CompanyName)
		if err != nil {
			stark.Logger.Errorf(ctx, "查询企业的工商信息失败,公司名:%s,错误信息:%s", request.CompanyName, err.Error())
			return errors.New("企业工商信息不存在，请核对后重新输入")
		}
		if companyDetail == nil || companyDetail.OrganizingCode == "" {
			return errors.New("企业工商信息不存在，请核对后重新输入")
		}
		request.OrganizingCode = companyDetail.OrganizingCode
	}
	return nil
}

func (s *clueService) ClueSave(ctx context.Context, request *pb.SaveClueRequest) (int64, error) {
	//检查线索公司名称是否存在,只有用户新增自建线索或编辑线索需要校验
	if request.Id != 0 || request.Source == constants.ClueSourceManual {
		err := s.getOrganizingCodeByCompanyName(ctx, request)
		if err != nil {
			return 0, err
		}
	}

	curUser := s.getCurUser(ctx)
	if request.Id == 0 {
		return s.saveNewClue(ctx, request)
	}
	//编辑已存在线索
	clueDetail, err := s.clueRepo.ClueDetail(ctx, request.Id)
	if err != nil {
		return 0, err
	}
	if clueDetail == nil {
		return 0, errors.New("线索不存在")
	}

	updates := s.buildClueUpdate(ctx, request)
	if len(updates) == 0 {
		return 0, errors.New("参数错误，无更新数据")
	}

	err = s.clueRepo.ClueUpdate(ctx,
		map[string]interface{}{"id": request.Id, "is_deleted": constants.IsDeletedFalse},
		updates)
	if err != nil {
		return 0, err
	}

	if request.InChargeUserId != 0 {
		// 更新线索负责人
		_, list, err := s.clueRepo.ClueTrackerQueryList(ctx,
			map[string]interface{}{"clue_id": request.Id, "is_in_charge": constants.IsInCharge, "is_deleted": constants.IsDeletedFalse},
			nil, "")
		if err != nil {
			return 0, err
		}
		if len(list) == 0 {
			//没有线索负责人，则新增一个
			_, err = s.clueRepo.ClueTrackerSave(ctx, &clue.GfyxClueTrackerPo{
				Id:         0,
				ClueId:     request.Id,
				UserId:     request.InChargeUserId,
				IsInCharge: constants.IsInCharge,
				CreatedBy:  curUser.UserId,
				CreatedOn:  time.Now(),
				ModifiedBy: curUser.UserId,
				ModifiedOn: time.Now(),
				IsDeleted:  constants.IsDeletedFalse,
			})
			if err != nil {
				return 0, err
			}
		} else {
			//已有线索负责人，比对线索负责人是否变更
			curInChargeUserId := list[0].UserId
			if curInChargeUserId != request.InChargeUserId {
				err = s.clueRepo.ClueTrackerUpdate(ctx, map[string]interface{}{"id": list[0].Id}, map[string]interface{}{"user_id": request.InChargeUserId, "modified_on": time.Now()})
				if err != nil {
					return 0, err
				}
			}
		}
	}

	return request.Id, nil
}

func (s *clueService) buildClueUpdate(_ context.Context, request *pb.SaveClueRequest) map[string]interface{} {
	if request == nil {
		return nil
	}
	updates := make(map[string]interface{})

	if request.CompanyName != "" {
		//更新公司名称和社会信用代码，如果新输入的公司名称没有社会信用代码，那就需要把旧的社会信用代码清空
		updates["company_name"] = request.CompanyName
		if request.OrganizingCode != "" {
			updates["organizing_code"] = request.OrganizingCode
		} else {
			updates["organizing_code"] = ""
		}
	}

	if request.Status != 0 {
		updates["status"] = request.Status
	}
	if request.ContactName != "" {
		updates["contact_name"] = request.ContactName
	}
	if request.ContactPosition != "" {
		updates["contact_position"] = request.ContactPosition
	}

	if request.ProvinceCode != "" {
		updates["province_code"] = request.ProvinceCode
	}
	if request.CityCode != "" {
		updates["city_code"] = request.CityCode
	}

	if len(updates) > 0 {
		updates["modified_on"] = time.Now()
	}

	return updates
}

func (s *clueService) saveNewClue(ctx context.Context, request *pb.SaveClueRequest) (int64, error) {
	curUser := s.getCurUser(ctx)
	cluePo := &clue.GfyxCluePo{
		Id:              request.Id,
		CompanyName:     request.CompanyName,
		OrganizingCode:  request.OrganizingCode,
		Status:          request.Status,
		Source:          request.Source,
		SourceId:        request.SourceId,
		SourceTitle:     request.SourceTitle,
		ProvinceCode:    request.ProvinceCode,
		CityCode:        request.CityCode,
		ContactName:     request.ContactName,
		ContactMobile:   request.ContactMobile,
		ContactPosition: request.ContactPosition,
		FromDevice:      utils.GetDevice(ctx),
		CreatedBy:       curUser.UserId,
		CreatedOn:       time.Now(),
		ModifiedBy:      curUser.UserId,
		ModifiedOn:      time.Now(),
		IsDeleted:       constants.IsDeletedFalse,
	}

	// 线索唯一性校验：联系人手机号+创建人id
	_, list, _ := s.clueRepo.ClueQueryList(ctx,
		map[string]interface{}{
			"a.contact_mobile": request.ContactMobile,
			"a.created_by":     curUser.UserId,
			"a.is_deleted":     constants.IsDeletedFalse,
		}, nil)
	if len(list) > 0 {
		// 线索已经存在，不再新建，直接返回已存在的线索id
		return list[0].Id, nil
	}

	// 保存线索
	cluePo, err := s.clueRepo.ClueSave(ctx, cluePo)
	if err != nil {
		return 0, err
	}

	// 保存联系人
	if request.ContactMobile != "" {
		_, err = s.clueRepo.ClueContactSave(ctx, &clue.GfyxClueContactPo{
			Id:          0,
			ClueId:      cluePo.Id,
			Mobile:      request.ContactMobile,
			Name:        request.ContactName,
			CompanyName: request.CompanyName,
			Position:    request.ContactPosition,
			CreatedBy:   curUser.UserId,
			CreatedOn:   time.Now(),
			ModifiedBy:  curUser.UserId,
			ModifiedOn:  time.Now(),
			IsDeleted:   constants.IsDeletedFalse,
		})
		if err != nil {
			return 0, err
		}
	}

	// 保存跟进人&&负责人
	if request.InChargeUserId != 0 {
		_, err = s.clueRepo.ClueTrackerSave(ctx, &clue.GfyxClueTrackerPo{
			Id:         0,
			ClueId:     cluePo.Id,
			UserId:     request.InChargeUserId,
			IsInCharge: constants.IsInCharge,
			CreatedBy:  curUser.UserId,
			CreatedOn:  time.Now(),
			ModifiedBy: curUser.UserId,
			ModifiedOn: time.Now(),
			IsDeleted:  constants.IsDeletedFalse,
		})
		if err != nil {
			return 0, err
		}
	}

	// 新增线索，更新商机状态为已转线索
	if request.SourceId != "" {
		updateOpptyStatusRequest := &businessOpportunityPb.UpdateOpptyStatusRequest{
			DataSourceId: request.SourceId,
			Status:       constants.OpptyStatusClue,
			FromDevice:   utils.GetDevice(ctx),
		}
		switch request.Source {
		case constants.ClueSourceBid:
			updateOpptyStatusRequest.DataSource = constants.OpptySourcePurchase
		case constants.ClueSourceWinbid:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceWinBid
		case constants.ClueSourceLand:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceLand
		case constants.ClueSourceBuilding:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceBuilding
		case constants.ClueSourceSale:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceSale
		case constants.ClueSourceCustomer:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceCustomer
		case constants.ClueSourceProject:
			updateOpptyStatusRequest.DataSource = constants.OpptySourceProjectCycle
		}
		_, _ = s.opptyStatusService.UpdateOpptyStatus(ctx, updateOpptyStatusRequest)
	}

	err = s.clueToCrm(ctx, cluePo)
	if err != nil {
		stark.Logger.Errorf(ctx, "添加线索转至客户crm系统时出错，线索:%#v, 错误信息:%s", cluePo, err)
	}
	return cluePo.Id, nil
}

func (s *clueService) DeleteClue(ctx context.Context, request *pb.DeleteClueRequest) error {
	if request == nil || request.Id == 0 {
		return errors.New("参数错误")
	}

	return s.clueRepo.ClueUpdate(ctx, map[string]interface{}{"id": request.Id}, map[string]interface{}{"is_deleted": constants.IsDeletedTrue, "modified_on": time.Now()})
}

func (s *clueService) GetClueDetailByClueId(ctx context.Context, clueId int64) (*pb.GetClueDetailByClueIdResponse, error) {
	var resp pb.GetClueDetailByClueIdResponse
	clueDetail, err := s.clueRepo.ClueDetail(ctx, clueId)
	if err != nil {
		return nil, err
	}
	if clueDetail == nil {
		return nil, errors.New("线索不存在")
	}
	clueDetailPb := &pb.ClueDetail{
		Id:               clueDetail.Id,
		CompanyName:      clueDetail.CompanyName,
		OrganizingCode:   clueDetail.OrganizingCode,
		Status:           clueDetail.Status,
		Source:           clueDetail.Source,
		SourceId:         clueDetail.SourceId,
		SourceTitle:      clueDetail.SourceTitle,
		ProvinceCode:     clueDetail.ProvinceCode,
		CityCode:         clueDetail.CityCode,
		Address:          "",
		Province:         "",
		City:             "",
		CreatedUsername:  "",
		CreatedOn:        clueDetail.CreatedOn.Format("2006-01-02 15:04:05"),
		InChargeUsername: "",
		ContactName:      clueDetail.ContactName,
		ContactMobile:    clueDetail.ContactMobile,
		ContactPosition:  clueDetail.ContactPosition,
	}

	var areaCodes []string
	if clueDetail.ProvinceCode != "" {
		areaCodes = append(areaCodes, clueDetail.ProvinceCode)
	}
	if clueDetail.CityCode != "" {
		areaCodes = append(areaCodes, clueDetail.CityCode)
	}

	if len(areaCodes) != 0 {
		areaList, _ := s.areaRepo.GetAreaInfoByItemCode(ctx, areaCodes)
		for _, item := range areaList {
			if item.ItemCode == clueDetail.ProvinceCode {
				clueDetailPb.Province = item.NormName
			} else if item.ItemCode == clueDetail.CityCode {
				clueDetailPb.City = item.NormName
			}
		}
		if clueDetailPb.Province == clueDetailPb.City {
			clueDetailPb.Address = clueDetailPb.Province
		} else {
			clueDetailPb.Address = clueDetailPb.Province + clueDetailPb.City
		}
	}

	if clueDetail.CreatedBy != 0 {
		userInfo, _ := s.userNewRepos.UserDetailByUserId(ctx, clueDetail.CreatedBy)
		if userInfo != nil && userInfo.Id != 0 {
			clueDetailPb.CreatedUsername = userInfo.Name
		}
	}
	if clueDetailPb.Source == constants.ClueSourceOutbound {
		clueDetailPb.CreatedUsername = "AI外呼"
		clueDetailPb.SourceTitle = "AI外呼"
		clueDetailPb.SourceId = fmt.Sprintf("%d", clueDetailPb.Id)
	} else if clueDetailPb.Source == constants.ClueSourceManual {
		clueDetailPb.SourceTitle = "用户自建"
		clueDetailPb.SourceId = fmt.Sprintf("%d", clueDetailPb.Id)
	}

	//查询线索负责人
	_, trackerList, err := s.clueRepo.ClueTrackerQueryList(ctx,
		map[string]interface{}{
			"clue_id":      clueDetail.Id,
			"is_in_charge": constants.IsInCharge,
			"is_deleted":   constants.IsDeletedFalse}, &utils.PageInfo{Page: 1, PageSize: 1}, "")
	if err != nil {
		return nil, err
	}
	if len(trackerList) > 0 {
		userInfo, _ := s.userNewRepos.UserDetailByUserId(ctx, trackerList[0].UserId)
		if userInfo != nil && userInfo.Id != 0 {
			clueDetailPb.InChargeUsername = userInfo.Name
			clueDetailPb.InChargeUserId = userInfo.Id
		}
	}

	if clueDetail.OrganizingCode != "" {
		//公司的社会信用代码不为空，则从客户主档案中获取公司信息
		details, _ := s.openSearchRepos.GetCustomerDetail(ctx, &opensearch_remote.GetCustomerDetailRequest{OrganizingCodes: clueDetail.OrganizingCode})
		if len(details) > 0 {
			clueDetailPb.CompanyType = details[0].CompanyType
			clueDetailPb.EstablishDate = details[0].EstablishDate
			clueDetailPb.LegalName = details[0].LegalName
			clueDetailPb.CompanyAddress = details[0].Address
		}

	}

	resp.Clue = clueDetailPb
	return &resp, nil
}

func (s *clueService) buildClueQueryCondition(ctx context.Context, request *pb.GetClueListRequest) map[string]interface{} {
	if request == nil {
		return nil
	}
	curUser := s.getCurUser(ctx)
	condition := make(map[string]interface{})

	if curUser.UserId == 0 && curUser.TenantUserUid != "" {
		//小程序端的用户id可能是空的，那就用guid查一次用户id
		_, userList, _ := s.userNewRepos.QueryUserList(ctx, map[string]interface{}{"user_guids": []string{curUser.TenantUserUid}}, nil, "")
		if len(userList) > 0 {
			curUser.UserId = userList[0].Id
		}
	}

	if request.Keyword != "" {
		condition["keyword"] = request.Keyword
	}
	if len(request.AreaCodeList) != 0 {
		condition["area_code_list"] = request.AreaCodeList
	}
	if len(request.StatusList) != 0 {
		condition["status_list"] = request.StatusList
	}

	if request.UseCase == 1 {
		// 我的线索：查询当前登录用户在跟进团队内的线索
		condition["charge_user_ids"] = []int64{curUser.UserId}
	} else if request.UseCase == 2 {
		// 区域线索：查询当前登录用户负责的区域以及所有子区域的所有用户id,这些用户id在跟进团队内的线索
		var userIds []int64
		subUserIds, _ := s.userOrgRepos.GetMyResponseOrgUserIds(ctx, curUser.UserId)
		userIds = append(userIds, subUserIds...)
		subUserIds, _ = s.userOrgRepos.GetMyResponseSubOrgUserIds(ctx, curUser.UserId)
		userIds = append(userIds, subUserIds...)
		if len(userIds) != 0 {
			condition["charge_user_ids"] = userIds
		}
	} else if request.UseCase == 3 {
		// ai外呼线索列表
		condition["source"] = constants.ClueSourceOutbound
		if request.Assigned != 0 {
			condition["assigned"] = request.Assigned
		}
		if len(request.InChargeUserIdList) != 0 {
			condition["charge_user_ids"] = request.InChargeUserIdList
		}
	}

	return condition
}

func (s *clueService) ClueList(ctx context.Context, request *pb.GetClueListRequest) (*pb.GetClueListResponse, error) {
	var resp pb.GetClueListResponse
	condition := s.buildClueQueryCondition(ctx, request)

	//获取全部线索，但是现在负责人id为空时，直接返回空列表
	if request.UseCase == 2 {
		_, ok := condition["charge_user_ids"]
		if !ok {
			return &resp, nil
		}
	}

	pageInfo := &utils.PageInfo{Page: 1, PageSize: 20}
	if request.Page > 0 {
		pageInfo.Page = int(request.Page)
	}
	if request.PageSize > 0 {
		pageInfo.PageSize = int(request.PageSize)
	}
	total, list, err := s.clueRepo.ClueQueryList(ctx, condition, pageInfo)
	if err != nil {
		return nil, err
	}

	resp.Total = int32(total)

	if len(list) == 0 {
		return &resp, nil
	}

	var clueIds []int64
	var userIds []int64
	userIdSet := make(map[int64]bool)
	var areaCodes []string
	areaCodeSet := make(map[string]bool)
	for _, item := range list {
		if item.ProvinceCode != "" {
			if _, ok := areaCodeSet[item.ProvinceCode]; !ok {
				areaCodes = append(areaCodes, item.ProvinceCode)
				areaCodeSet[item.ProvinceCode] = true
			}
		}
		if item.CityCode != "" {
			if _, ok := areaCodeSet[item.CityCode]; !ok {
				areaCodes = append(areaCodes, item.CityCode)
			}
		}
		if item.CreatedBy != 0 {
			if _, ok := userIdSet[item.CreatedBy]; !ok {
				userIds = append(userIds, item.CreatedBy)
				userIdSet[item.CreatedBy] = true
			}
		}

		clueIds = append(clueIds, item.Id)
	}

	//查线索负责人
	_, trackerList, err := s.clueRepo.ClueTrackerQueryList(ctx,
		map[string]interface{}{
			"clue_ids":     clueIds,
			"is_in_charge": constants.IsInCharge,
			"is_deleted":   constants.IsDeletedFalse}, nil, "")
	if err != nil {
		return nil, err
	}

	clueId2InChargeUserId := make(map[int64]int64)
	for _, trackerPo := range trackerList {
		if trackerPo.UserId != 0 {
			if _, ok := userIdSet[trackerPo.UserId]; !ok {
				userIds = append(userIds, trackerPo.UserId)
				userIdSet[trackerPo.UserId] = true
			}
			clueId2InChargeUserId[trackerPo.ClueId] = trackerPo.UserId
		}
	}

	//根据用户id批量获取用户信息
	_, userList, err := s.userNewRepos.QueryUserList(ctx,
		map[string]interface{}{"user_ids": userIds, "is_deleted": constants.IsDeletedFalse},
		nil, "")
	if err != nil {
		return nil, err
	}

	userId2UserInfo := make(map[int64]*userRepo.GfyxUserPo)
	for _, userPo := range userList {
		if userPo == nil {
			continue
		}
		userId2UserInfo[userPo.Id] = userPo
	}

	areaConfigList, err := s.areaRepo.GetAreaInfoByItemCode(ctx, areaCodes)
	if err != nil {
		return nil, err
	}
	areaCode2AreaConfig := make(map[string]*area.GfyxAreaConfigPo)
	for _, areaConfigPo := range areaConfigList {
		if areaConfigPo == nil {
			continue
		}
		areaCode2AreaConfig[areaConfigPo.ItemCode] = areaConfigPo
	}

	for _, item := range list {
		if item == nil {
			continue
		}
		clueDetailPb := s.cluePo2Pb(ctx, item)
		if clueDetailPb == nil {
			continue
		}
		if areaConfig, ok := areaCode2AreaConfig[item.ProvinceCode]; ok {
			clueDetailPb.Province = areaConfig.NormName
		}
		if areaConfig, ok := areaCode2AreaConfig[item.CityCode]; ok {
			clueDetailPb.City = areaConfig.NormName
		}
		if clueDetailPb.Province == clueDetailPb.City {
			clueDetailPb.Address = clueDetailPb.Province
		} else {
			clueDetailPb.Address = clueDetailPb.Province + clueDetailPb.City
		}

		if userPo, ok := userId2UserInfo[item.CreatedBy]; ok {
			clueDetailPb.CreatedUsername = userPo.Name
		}

		if inChargeUserId, ok := clueId2InChargeUserId[item.Id]; ok {
			if userPo, ok := userId2UserInfo[inChargeUserId]; ok {
				clueDetailPb.InChargeUsername = userPo.Name
			}
		}

		resp.List = append(resp.List, clueDetailPb)
	}

	return &resp, nil
}

func (s *clueService) cluePo2Pb(ctx context.Context, cluePo *clue.GfyxCluePo) *pb.ClueDetail {
	if cluePo == nil {
		return nil
	}
	cluePb := &pb.ClueDetail{
		Id:               cluePo.Id,
		CompanyName:      cluePo.CompanyName,
		OrganizingCode:   cluePo.OrganizingCode,
		Status:           cluePo.Status,
		Source:           cluePo.Source,
		SourceId:         cluePo.SourceId,
		SourceTitle:      cluePo.SourceTitle,
		ProvinceCode:     cluePo.ProvinceCode,
		CityCode:         cluePo.CityCode,
		Province:         "",
		City:             "",
		CreatedUsername:  "",
		CreatedOn:        cluePo.CreatedOn.Format("2006-01-02 15:04:05"),
		InChargeUsername: "",
		ContactName:      cluePo.ContactName,
		ContactMobile:    cluePo.ContactMobile,
		ContactPosition:  cluePo.ContactPosition,
	}
	//查线索是否有人为的跟进记录
	// 这个没有通过线索id去分批查，主要是因为一条线索可能有很多跟进记录，那么查询的时候，数据量可能会很多
	count, _, _ := s.clueRepo.ClueFollowRecordQueryList(ctx,
		map[string]interface{}{
			"clue_id":     cluePo.Id,
			"from_source": constants.ClueFollowFromSourceHuman,
			"is_deleted":  constants.IsDeletedFalse}, &utils.PageInfo{Page: 1, PageSize: 1})
	if count > 0 {
		cluePb.HasHumanFollow = true
	}
	//查询最新的一条跟进记录
	_, latestFollowRecordList, _ := s.clueRepo.ClueFollowRecordQueryList(ctx,
		map[string]interface{}{
			"clue_id":    cluePo.Id,
			"is_deleted": constants.IsDeletedFalse}, &utils.PageInfo{Page: 1, PageSize: 1})
	if len(latestFollowRecordList) > 0 {
		userInfo, _ := s.userNewRepos.UserDetailByUserId(ctx, latestFollowRecordList[0].CreatedBy)
		username := ""
		if userInfo != nil && userInfo.Name != "" {
			username = userInfo.Name
		}
		cluePb.LatestFollow = &pb.LatestFollow{
			FollowTime: latestFollowRecordList[0].CreatedOn.Format("2006-01-02 15:04:05"),
			Content:    latestFollowRecordList[0].Content,
			Username:   username,
		}
	}
	if cluePb.Source == constants.ClueSourceOutbound {
		cluePb.CreatedUsername = "AI外呼"
		cluePb.SourceTitle = "AI外呼"
		cluePb.SourceId = fmt.Sprintf("%d", cluePb.Id)
	} else if cluePb.Source == constants.ClueSourceManual {
		cluePb.SourceTitle = "用户自建"
		cluePb.SourceId = fmt.Sprintf("%d", cluePb.Id)
	}

	return cluePb
}

func (s *clueService) SaveClueTracker(ctx context.Context, request *pb.SaveClueTrackerRequest) (int64, error) {
	if request == nil || request.ClueId == 0 || request.UserId == 0 {
		return 0, errors.New("参数不能为空")
	}
	//检查跟进人是否重复
	count, _, err := s.clueRepo.ClueTrackerQueryList(ctx, map[string]interface{}{"clue_id": request.ClueId, "user_id": request.UserId, "is_deleted": constants.IsDeletedFalse}, nil, "")
	if err != nil {
		return 0, err
	}
	if count > 0 {
		return 0, errors.New("跟进人已存在，请勿重复添加")
	}

	curUser := s.getCurUser(ctx)
	if request.IsInCharge != constants.IsInCharge {
		request.IsInCharge = constants.NotInCharge
	}
	trackerPo, err := s.clueRepo.ClueTrackerSave(ctx, &clue.GfyxClueTrackerPo{
		Id:         0,
		ClueId:     request.ClueId,
		UserId:     request.UserId,
		IsInCharge: request.IsInCharge,
		CreatedBy:  curUser.UserId,
		CreatedOn:  time.Now(),
		ModifiedBy: curUser.UserId,
		ModifiedOn: time.Now(),
		IsDeleted:  constants.IsDeletedFalse,
	})
	if err != nil {
		return 0, err
	}

	if trackerPo == nil {
		return 0, errors.New("添加跟进人失败")
	}

	return trackerPo.Id, nil
}

func (s *clueService) GetClueTrackerList(ctx context.Context, request *pb.GetClueTrackerListRequest) (*pb.GetClueTrackerListResponse, error) {
	if request == nil || request.ClueId == 0 {
		return nil, errors.New("参数不能为空")
	}
	count, list, err := s.clueRepo.ClueTrackerQueryList(ctx,
		map[string]interface{}{"clue_id": request.ClueId, "is_deleted": constants.IsDeletedFalse},
		&utils.PageInfo{
			Page:     int(request.Page),
			PageSize: int(request.PageSize),
		}, "is_in_charge,id desc",
	)
	if err != nil {
		return nil, err
	}
	resp := &pb.GetClueTrackerListResponse{Total: int32(count)}

	var userIds []int64
	userIdSet := make(map[int64]bool)
	for _, trackerPo := range list {
		if trackerPo.UserId != 0 {
			if _, ok := userIdSet[trackerPo.UserId]; !ok {
				userIds = append(userIds, trackerPo.UserId)
				userIdSet[trackerPo.UserId] = true
			}
		}
	}

	_, userList, err := s.userNewRepos.QueryUserList(ctx, map[string]interface{}{"user_ids": userIds, "is_deleted": constants.IsDeletedFalse}, nil, "")
	if err != nil {
		return nil, err
	}

	userId2UserInfo := make(map[int64]*userRepo.GfyxUserPo)
	for _, userPo := range userList {
		if userPo == nil {
			continue
		}
		userId2UserInfo[userPo.Id] = userPo
	}

	for _, trackerPo := range list {
		trackerPb := &pb.ClueTracker{
			Id:         trackerPo.Id,
			ClueId:     trackerPo.ClueId,
			UserId:     trackerPo.UserId,
			IsInCharge: trackerPo.IsInCharge,
		}
		if userPo, ok := userId2UserInfo[trackerPo.UserId]; ok {
			trackerPb.Name = userPo.Name
		}
		resp.List = append(resp.List, trackerPb)
	}
	return resp, nil
}

func (s *clueService) DeleteClueTracker(ctx context.Context, request *pb.DeleteClueTrackerRequest) error {
	//先判断是否是负责人，如果是负责人，不允许直接删除
	trackerPo, err := s.clueRepo.ClueTrackerFindById(ctx, request.Id)
	if err != nil {
		return err
	}
	if trackerPo == nil {
		return errors.New("跟进人不存在")
	}
	if trackerPo.IsInCharge == constants.IsInCharge {
		return errors.New("负责人不能删除，请先更换负责人")
	}
	return s.clueRepo.ClueTrackerUpdate(ctx, map[string]interface{}{"id": request.Id}, map[string]interface{}{"is_deleted": constants.IsDeletedTrue, "modified_on": time.Now()})
}

func (s *clueService) ReplaceChargeUser(ctx context.Context, request *pb.ReplaceChargeUserRequest) error {
	if request == nil || request.ClueId == 0 || request.UserId == 0 {
		return errors.New("参数错误")
	}
	condition := map[string]interface{}{
		"clue_id":      request.ClueId,
		"is_in_charge": constants.IsInCharge,
		"is_deleted":   constants.IsDeletedFalse,
	}
	//如果已有负责人，则替换已有负责人，如果没有负责人，则新建线索跟进人，身份是负责人
	_, list, err := s.clueRepo.ClueTrackerQueryList(ctx, condition, &utils.PageInfo{Page: 1, PageSize: 1}, "")
	if err != nil {
		return err
	}
	if len(list) > 0 {
		inChargeUserId := list[0].UserId
		if inChargeUserId == request.UserId {
			return nil
		}
		//如果已有负责人，则替换已有负责人
		//替换前，看看新的负责人是否在跟进团队中，如果在，就删除旧的负责人，把新的用户更新为负责人，如果不在，就把旧的负责人替换为新的
		condition2 := map[string]interface{}{
			"clue_id":    request.ClueId,
			"user_id":    request.UserId,
			"is_deleted": constants.IsDeletedFalse,
		}
		count2, _, err := s.clueRepo.ClueTrackerQueryList(ctx, condition2, &utils.PageInfo{Page: 1, PageSize: 1}, "")
		if err != nil {
			return err
		}
		if count2 > 0 {
			//新的负责人在跟进团队中
			err = s.clueRepo.ClueTrackerUpdate(ctx, condition, map[string]interface{}{"is_deleted": constants.IsDeletedTrue, "modified_on": time.Now()})
			if err != nil {
				return nil
			}
			err = s.clueRepo.ClueTrackerUpdate(ctx, condition2, map[string]interface{}{"is_in_charge": constants.IsInCharge, "modified_on": time.Now()})
			if err != nil {
				return nil
			}
		} else {
			//新的负责人不在跟进团队中
			err = s.clueRepo.ClueTrackerUpdate(ctx, condition, map[string]interface{}{"user_id": request.UserId, "modified_on": time.Now()})
			if err != nil {
				return err
			}
		}
	} else {
		//如果没有负责人，则新建线索跟进人，身份是负责人
		condition2 := map[string]interface{}{
			"clue_id":    request.ClueId,
			"user_id":    request.UserId,
			"is_deleted": constants.IsDeletedFalse,
		}
		count2, _, err := s.clueRepo.ClueTrackerQueryList(ctx, condition2, &utils.PageInfo{Page: 1, PageSize: 1}, "")
		if err != nil {
			return err
		}
		if count2 > 0 {
			//新的负责人在跟进团队中，身份更新为负责人
			err = s.clueRepo.ClueTrackerUpdate(ctx, condition2, map[string]interface{}{"is_in_charge": constants.IsInCharge, "modified_on": time.Now()})
			if err != nil {
				return nil
			}
		} else {
			//新的负责人不在跟进团队中，新建线索跟进人，身份是负责人
			_, err = s.SaveClueTracker(ctx, &pb.SaveClueTrackerRequest{
				ClueId:     request.ClueId,
				UserId:     request.UserId,
				IsInCharge: constants.IsInCharge,
			})
			if err != nil {
				return err
			}
		}

	}
	return nil
}

func (s *clueService) saveNewClueContact(ctx context.Context, request *pb.SaveClueContactRequest) (int64, error) {
	//判断联系人是否存在
	count, _, err := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{"clue_id": request.ClueId, "mobile": request.Mobile, "is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return 0, err
	}
	if count > 0 {
		return 0, errors.New("联系电话已存在，请勿重复添加")
	}
	curUser := s.getCurUser(ctx)
	contactPo, err := s.clueRepo.ClueContactSave(ctx, &clue.GfyxClueContactPo{
		Id:          0,
		ClueId:      request.ClueId,
		Name:        request.Name,
		CompanyName: request.CompanyName,
		Position:    request.Position,
		Mobile:      request.Mobile,
		CreatedBy:   curUser.UserId,
		CreatedOn:   time.Now(),
		ModifiedBy:  curUser.UserId,
		ModifiedOn:  time.Now(),
		IsDeleted:   constants.IsDeletedFalse,
	})
	if err != nil {
		return 0, err
	}

	if contactPo == nil || contactPo.Id == 0 {
		return 0, errors.New("添加联系人失败")
	}
	return contactPo.Id, nil
}

func (s *clueService) SaveClueContact(ctx context.Context, request *pb.SaveClueContactRequest) (int64, error) {
	if request == nil || request.ClueId == 0 || request.Mobile == "" {
		return 0, errors.New("参数错误")
	}

	if request.Id == 0 {
		//新增联系人
		return s.saveNewClueContact(ctx, request)
	}
	//编辑联系人
	condition := map[string]interface{}{
		"id":         request.Id,
		"is_deleted": constants.IsDeletedFalse,
	}
	updates := map[string]interface{}{"modified_on": time.Now()}
	updates["position"] = request.Position //职位允许为空

	if request.Name != "" {
		updates["name"] = request.Name
	}
	if request.CompanyName != "" {
		updates["company_name"] = request.CompanyName
	}
	err := s.clueRepo.ClueContactUpdate(ctx, condition, updates)
	if err != nil {
		return 0, err
	}

	return request.Id, nil
}

func (s *clueService) GetClueContactList(ctx context.Context, request *pb.GetClueContactListRequest) (*pb.GetClueContactListResponse, error) {

	if request == nil || request.ClueId == 0 {
		return nil, errors.New("参数错误")
	}
	total, list, err := s.clueRepo.ClueContactQueryList(ctx,
		map[string]interface{}{"clue_id": request.ClueId, "is_deleted": constants.IsDeletedFalse},
		&utils.PageInfo{
			PageSize: int(request.PageSize),
			Page:     int(request.Page),
		})
	if err != nil {
		return nil, err
	}

	resp := &pb.GetClueContactListResponse{Total: int32(total)}
	for _, contactPo := range list {
		resp.List = append(resp.List, &pb.ClueContact{
			Id:          contactPo.Id,
			ClueId:      contactPo.ClueId,
			Name:        contactPo.Name,
			CompanyName: contactPo.CompanyName,
			Position:    contactPo.Position,
			Mobile:      contactPo.Mobile,
		})
	}
	return resp, nil
}

func (s *clueService) DeleteClueContact(ctx context.Context, request *pb.DeleteClueContactRequest) error {
	if request == nil || request.Id == 0 {
		return errors.New("参数错误")
	}
	_, contactList, err := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{"id": request.Id, "is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return err
	}
	if len(contactList) == 0 {
		return errors.New("联系人不存在")
	}
	contactDetail := contactList[0]
	count, _, err := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{"clue_id": contactDetail.ClueId, "is_deleted": constants.IsDeletedFalse}, &utils.PageInfo{Page: 1, PageSize: 1})
	if err != nil {
		return err
	}

	if count == 1 {
		return errors.New("不允许删除最后一个联系人")
	}

	return s.clueRepo.ClueContactUpdate(ctx, map[string]interface{}{"id": request.Id}, map[string]interface{}{"is_deleted": constants.IsDeletedTrue})
}

func (s *clueService) GetClueContactDetailById(ctx context.Context, request *pb.GetClueContactDetailByIdRequest) (*pb.GetClueContactDetailByIdResponse, error) {
	if request == nil || request.Id == 0 {
		return nil, errors.New("参数错误")
	}
	_, contactList, err := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{"id": request.Id, "is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return nil, err
	}
	if len(contactList) == 0 {
		return nil, errors.New("联系人不存在")
	}
	contactDetail := contactList[0]
	return &pb.GetClueContactDetailByIdResponse{
		Detail: &pb.ClueContact{
			Id:          contactDetail.Id,
			ClueId:      contactDetail.ClueId,
			Name:        contactDetail.Name,
			CompanyName: contactDetail.CompanyName,
			Position:    contactDetail.Position,
			Mobile:      contactDetail.Mobile,
			CreatedOn:   contactDetail.CreatedOn.Format("2006-01-02 15:04:05"),
		},
	}, nil
}

func (s *clueService) AddClueFollowRecord(ctx context.Context, request *pb.AddClueFollowRecordRequest) (int64, error) {
	if request == nil || request.ClueId == 0 {
		return 0, errors.New("参数错误")
	}

	clueDetailPo, err := s.clueRepo.ClueDetail(ctx, request.ClueId)
	if err != nil {
		return 0, err
	}
	if clueDetailPo == nil {
		return 0, errors.New("线索不存在")
	}

	if clueDetailPo.Status == constants.ClueStatusClose {
		return 0, errors.New("线索已关闭")
	}

	curUser := s.getCurUser(ctx)
	followRecordPo, err := s.clueRepo.ClueSaveFollowRecord(ctx, &clue.GfyxClueFollowRecordPo{
		Id:               0,
		ClueId:           request.ClueId,
		ContactId:        request.ContactId,
		FollowType:       request.FollowType,
		ClueStatus:       request.ClueStatus,
		BeforeClueStatus: clueDetailPo.Status,
		Content:          request.Content,
		TalkContent:      request.TalkContent,
		FromSource:       request.FromSource,
		CreatedBy:        curUser.UserId,
		CreatedOn:        time.Now(),
		ModifiedBy:       curUser.UserId,
		ModifiedOn:       time.Now(),
		IsDeleted:        constants.IsDeletedFalse,
	})
	if err != nil {
		return 0, err
	}
	if followRecordPo == nil || followRecordPo.Id == 0 {
		return 0, errors.New("添加跟进记录失败")
	}

	//修改线索跟进状态
	if clueDetailPo.Status != followRecordPo.ClueStatus {
		err = s.clueRepo.ClueUpdate(ctx, map[string]interface{}{"id": request.ClueId, "is_deleted": constants.IsDeletedFalse},
			map[string]interface{}{"status": followRecordPo.ClueStatus, "modified_on": time.Now()})
		if err != nil {
			return 0, err
		}
	}
	return followRecordPo.Id, nil
}

func (s *clueService) GetClueFollowRecordList(ctx context.Context, request *pb.GetClueFollowRecordListRequest) (*pb.GetClueFollowRecordListResponse, error) {
	if request == nil || request.ClueId == 0 {
		return nil, errors.New("参数错误")
	}
	condition := map[string]interface{}{
		"clue_id":    request.ClueId,
		"is_deleted": constants.IsDeletedFalse,
	}
	pageInfo := &utils.PageInfo{
		PageSize: int(request.PageSize),
		Page:     int(request.Page),
	}
	total, list, err := s.clueRepo.ClueFollowRecordQueryList(ctx, condition, pageInfo)
	if err != nil {
		return nil, err
	}
	resp := &pb.GetClueFollowRecordListResponse{Total: int32(total)}
	if len(list) == 0 {
		return resp, nil
	}

	var userIds []int64 //跟进人的用户id
	userIdSet := make(map[int64]bool)
	var contactIds []int64 //跟进的联系人的id
	contactIdSet := make(map[int64]bool)

	for _, followRecordPo := range list {
		if followRecordPo == nil {
			continue
		}
		if followRecordPo.CreatedBy != 0 {
			if _, ok := userIdSet[followRecordPo.CreatedBy]; !ok {
				userIds = append(userIds, followRecordPo.CreatedBy)
				userIdSet[followRecordPo.CreatedBy] = true
			}
		}
		if followRecordPo.ContactId != 0 {
			if _, ok := contactIdSet[followRecordPo.ContactId]; !ok {
				contactIds = append(contactIds, followRecordPo.ContactId)
				contactIdSet[followRecordPo.ContactId] = true
			}
		}
	}

	_, userList, err := s.userNewRepos.QueryUserList(ctx, map[string]interface{}{"user_ids": userIds, "is_deleted": constants.IsDeletedFalse}, nil, "")
	if err != nil {
		return nil, err
	}
	userId2UserInfo := make(map[int64]*userRepo.GfyxUserPo)
	for _, userPo := range userList {
		if userPo == nil {
			continue
		}
		userId2UserInfo[userPo.Id] = userPo
	}

	_, contactList, err := s.clueRepo.ClueContactQueryList(ctx, map[string]interface{}{
		"ids":        contactIds,
		"is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return nil, err
	}
	contactId2ContactInfo := make(map[int64]*clue.GfyxClueContactPo)
	for _, contactPo := range contactList {
		if contactPo == nil {
			continue
		}
		contactId2ContactInfo[contactPo.Id] = contactPo
	}

	for _, followRecordPo := range list {
		if followRecordPo == nil {
			continue
		}
		followRecordPb := &pb.ClueFollowRecord{
			Id:           followRecordPo.Id,
			ClueId:       followRecordPo.ClueId,
			FollowType:   followRecordPo.FollowType,
			FollowStatus: followRecordPo.FollowStatus,
			ClueStatus:   followRecordPo.ClueStatus,
			Content:      followRecordPo.Content,
			TalkContent:  followRecordPo.TalkContent,
			FromSource:   followRecordPo.FromSource,
			ContactId:    followRecordPo.ContactId,
			CreatedOn:    followRecordPo.CreatedOn.Format("2006-01-02 15:04:05"),
		}
		follower, ok := userId2UserInfo[followRecordPo.CreatedBy]
		if ok {
			followRecordPb.CreatedUsername = follower.Name
		}
		if followRecordPo.FromSource == constants.ClueFollowFromSourceAi {
			followRecordPb.CreatedUsername = "AI外呼"
		}
		contact, ok := contactId2ContactInfo[followRecordPo.ContactId]
		if ok {
			followRecordPb.ContactName = contact.Name
			followRecordPb.ContactMobile = contact.Mobile
		}

		resp.List = append(resp.List, followRecordPb)
	}
	return resp, nil
}

func (s *clueService) GetInChargeUserList(ctx context.Context, _ *pb.GetInChargeUserListRequest) (*pb.GetInChargeUserListResponse, error) {
	inChargeUserIds, err := s.clueRepo.ClueTrackerOutboundInChargeUserIdList(ctx)
	if err != nil {
		return nil, err
	}
	resp := &pb.GetInChargeUserListResponse{
		Total: int32(len(inChargeUserIds)),
		List:  nil,
	}

	_, userList, err := s.userNewRepos.QueryUserList(ctx, map[string]interface{}{"user_ids": inChargeUserIds, "is_deleted": constants.IsDeletedFalse}, nil, "")
	if err != nil {
		return nil, err
	}
	for _, userPo := range userList {
		resp.List = append(resp.List, &pb.ClueTracker{
			UserId: userPo.Id,
			Name:   userPo.Name,
		})
	}
	return resp, nil
}

func (s *clueService) clueToCrm(ctx context.Context, cluePo *clue.GfyxCluePo) error {
	_, list, err := s.crmConfigRepo.Query(ctx, map[string]interface{}{"is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return err
	}
	if len(list) == 0 {
		return nil
	}

	hasCrmFlag, crmServer := crm.AllCrm.GetCRMBySystemName(list[0].System)
	if hasCrmFlag {
		clueId, err := crmServer.CreateClue(ctx, &contract5.CrmData{
			BusinessUid:             fmt.Sprintf("%d", cluePo.Id),
			BusinessType:            constants.CrmBusinessTypeClue,
			CompanyName:             cluePo.CompanyName,
			UserName:                cluePo.ContactName,
			UserMobile:              cluePo.ContactMobile,
			Province:                cluePo.ProvinceCode,
			ResponsiblePersonMobile: s.getCurUser(ctx).MobilePhone,
		}, nil)
		if err != nil {
			return err
		}

		err = s.crmRelationRepo.Save(ctx, &gfyxcrmrelation2.GfyxCrmRelationPo{
			Uid:          uuid.GetUUID(),
			BusinessUid:  fmt.Sprintf("%d", cluePo.Id),
			BusinessType: constants.CrmBusinessTypeClue,
			CrmUid:       clueId,
			CreatedOn:    time.Now(),
			CreatedBy:    "",
			ModifiedOn:   time.Now(),
			ModifiedBy:   "",
			IsDeleted:    constants.IsDeletedFalse,
		})
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *clueService) QueryExportClueBatchData(ctx context.Context, condition interface{}, batchNum, batchSize int32) (rowTitle []string, rowData [][]string, err error) {
	rowTitle = strings.Split(constants.JobSourceTypeClueExportFields, "，")
	var request *pb.ExportClueListRequest
	switch condition.(type) {
	case *pb.ExportClueListRequest:
		request = condition.(*pb.ExportClueListRequest)
	case string:
		request = &pb.ExportClueListRequest{}
		if condition.(string) != "" {
			err = json.Unmarshal([]byte(condition.(string)), request)
			if err != nil {
				stark.Logger.Errorf(ctx, "线索导出，获取导出查询条件失败,condition:%+v, err:%s", condition, err)
				return
			}
		}
	}

	var listResp *pb.GetClueListResponse
	listResp, err = s.ClueList(ctx, &pb.GetClueListRequest{
		Keyword:            request.Keyword,
		StatusList:         request.StatusList,
		AreaCodeList:       request.AreaCodeList,
		Page:               batchNum,
		PageSize:           batchSize,
		UseCase:            request.UseCase,
		InChargeUserIdList: request.InChargeUserIdList,
		Assigned:           request.Assigned,
	})
	if err != nil {
		stark.Logger.Errorf(ctx, "grpc ExportClueList ClueList request:%+v, err:%s", request, err.Error())
		return
	}
	if listResp == nil || listResp.Total == 0 {
		return
	}

	for _, clueDetail := range listResp.List {
		latest := ""
		if clueDetail.LatestFollow != nil {
			latest = fmt.Sprintf("%s %s", clueDetail.LatestFollow.FollowTime, clueDetail.LatestFollow.Content)
		}
		if clueDetail.Source == constants.ClueSourceOutbound {
			clueDetail.CreatedUsername = "AI外呼"
			clueDetail.SourceTitle = "AI外呼"
		} else if clueDetail.Source == constants.ClueSourceManual {
			clueDetail.SourceTitle = "用户自建"
		}

		rowData = append(rowData, []string{
			clueDetail.ContactName + clueDetail.ContactMobile,          //线索标题，
			constants.GetCLueStatusNameByStatusCode(clueDetail.Status), //线索状态，
			clueDetail.CompanyName,                                     //公司名称，
			clueDetail.ContactName,                                     //联系人，
			clueDetail.ContactMobile,                                   //联系电话，
			clueDetail.ContactPosition,                                 //职位，
			clueDetail.SourceTitle,                                     //线索来源，
			clueDetail.CreatedOn,                                       //创建时间，
			clueDetail.CreatedUsername,                                 //创建人，
			clueDetail.InChargeUsername,                                //负责人，
			latest,                                                     //最新跟进
		})
	}
	return
}

func (s *clueService) getCurUser(ctx context.Context) usermetadata.MetaUserInfo {
	curUser := usermetadata.GetMetaUserInfo(ctx)

	if curUser.UserId == 0 && curUser.TenantUserUid != "" {
		//小程序端的用户id可能是空的，那就用guid查一次用户id
		_, userList, _ := s.userNewRepos.QueryUserList(ctx, map[string]interface{}{"user_guids": []string{curUser.TenantUserUid}}, nil, "")
		if len(userList) > 0 {
			curUser.UserId = userList[0].Id
		}
	}
	return curUser
}
